package com.newly.gateway.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.newly.common.base.constants.CodeConstant;
import com.newly.common.base.constants.ServerUriConstant;
import com.newly.common.base.entity.R;
import com.newly.gateway.service.api.ILoginRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

@Configuration
@Slf4j
public class RouteConfig {

    @Autowired
    private ILoginRecord loginRecord;

    @Bean
    public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }

    @Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("login-route-id", r -> r.path(ServerUriConstant.NEWLY_AUTH_LOGIN)
                        .filters(f -> f.modifyResponseBody(String.class, String.class, (exchange, respBody) -> {

                            ServerHttpRequest request = exchange.getRequest();
                            MultiValueMap<String, String> queryParams = request.getQueryParams();
                            String username = queryParams.getFirst("username");

                            JSONObject jsonObject = JSONUtil.parseObj(respBody);
                            String token = jsonObject.getStr("access_token");
                            String tokenType = null;
                            Long expiresTime = null;

                            // 无法在请求体中拿到token说明的账号密码是错误的
                            if (StrUtil.isBlank(token)) {
                                loginRecord.generate(exchange, username, false);
                                // 清除redis中的租户
                                return Mono.just(JSONUtil.toJsonStr(R.fail("登录失败，用户名或密码错误！")));
                            }
                            expiresTime = jsonObject.getLong("expires_in");
                            tokenType = jsonObject.getStr("token_type");

                            /*
                            // 登录前操作(返回token前操作)，如果返回true则认为是前置处理成功
                            boolean preLogin = true;
                            if (newlySysProperties.isOpenLoginPre()) {
                                preLogin = loginService.preLogin(exchange);
                            }

                            // 登录后操作
                            if (newlySysProperties.isOpenLoginPost()) {
                                try {
                                    loginService.postLogin(exchange, preLogin);
                                } catch (Exception e) {
                                    log.error("记录登录后操作异常: ", e);
                                }
                            }*/

                            R result = null;
                            if (true) {
                                Map<String, Object> data = new HashMap();
                                data.put("token", token);
                                data.put("expire", expiresTime);
                                data.put("type", tokenType);
                                result = R.ok(data);
                            } else {
                                // 未通过黑名单校验不返回token
                                result = R.fail(CodeConstant.BLACK_NAME, "拒绝访问,请联系管理员！");
                            }

                            loginRecord.generate(exchange, username, true);

                            return Mono.just(JSONUtil.toJsonStr(result));
                        })).uri("lb://newly-sys")
                )
//                .route("newly_user", r -> r.path("/tenant/**")
//                        .filters(f -> f.setPath("/tenant/**"))
//                        .uri("lb://newly-user"))
                .build();
    }
}
